#pragma once

#include<set>
#include <vector>
#include <list>

#include <windows.h> // for "cls"

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the BOMBMANCORE_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// BOMBMANCORE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef BOMBMANCORE_EXPORTS
#define BOMBMANCORE_API __declspec(dllexport)
#else
#define BOMBMANCORE_API __declspec(dllimport)
#endif

// This class is exported from the BombManCore.dll
class BOMBMANCORE_API CBombManCore {
public:
	CBombManCore(void);
	// TODO: add your methods here.
};

extern BOMBMANCORE_API int nBombManCore;

BOMBMANCORE_API int fnBombManCore(void);

/////////////////////////////////////////////////////////////////////

class BOMBMANCORE_API Map;
//         2 wall , 1 block , 0 null 
//w through  no        no      yes
//can fire   no        yes     yes
//f through  no        no      yes

class BOMBMANCORE_API Position
{
	int x;
	int y;
public:
	Position(int _x, int _y)
	{
		x = _x;
		y = _y;
	}
	void set_position(int _x, int _y)
	{
		x = _x;
		y = _y;
	};

	void set_position(const Position & _p)
	{
		x = _p.get_x();
		y = _p.get_y();
	}
	int get_x()const{return x;};
	int get_y()const{return y;};

	Position get_position(){return Position(*this);};

	void move_up(){y--;};
	void move_down(){y++;};
	void move_left(){x--;};
	void move_right(){x++;};

	Position my_left(){return Position(x-1,y);};
	Position my_right(){return Position(x+1,y);};
	Position my_up(){return Position(x,y-1);};
	Position my_down(){return Position(x,y+1);};

	bool is_left_side(){return x<=0;};
	bool is_right_side(int width){return x >= width-1;};
	bool is_up_side(){return y<=0;};
	bool is_down_side(int height){return y >= height-1;};
};

class BOMBMANCORE_API Radar:public Position
{
	Map* m_m;
public:
	enum Detected_Object
	{
		Detected_Wall,
		Detected_brick,
		Detected_Bomb,
		Detected_Fire,
		Detected_Man,
		Detected_Unknow
	};
	typedef struct Detected
	{
		Detected_Object obj;
		int distance;
		Detected()
		{
			obj = Detected_Unknow;
			distance = -1;
		}
	}Detected;

	Radar(Map* _m,Position &_p);
	Detected detect_up();
	Detected detect_down();
	Detected detect_left();
	Detected detect_right();
};

class BOMBMANCORE_API Creature:public Radar
{
	friend class Map;
	Map* m_m;
	int dead_count;
	int m_index;
	int m_bomb_power;
	int m_protect_time;
private:
	void on_die();
	void on_born();
public:
	Creature(int _index,Map *_m);
	~Creature();
	bool move_left();
	bool move_right();
	bool move_up();
	bool move_down();
	void set_bomb();
	void explode();
	bool is_protectd(){return m_protect_time > 0;};
	int get_index(){return m_index;};


	void ui_update();
	int get_dead_count(){return dead_count;};
};

class BOMBMANCORE_API Map
{
public:
	class BOMBMANCORE_API Tiled
	{
		
		//bool m_can_walk_through;
		//bool m_can_walk_through;
		//bool m_can_fire;
		
	public:
		bool m_fire;
		int m_put_bomb;
		long m_bomb_life;
		long m_fire_life;
		int m_bomb_power;
		int m_p;
		Tiled();

		bool can_walk_through();
		bool can_fire();
		//for starting show fire
		//for change the tiled
		void fire();
		//for stoping show fire
		void fire_off();

		bool is_fire();
		//for checking whether fire this bomb
		bool is_put_bomb();
		int get_bomb_puter();
		//for checking whether fire this bomb
		void put_bomb(int _man_index,long _bomb_power);
		long get_bomb_life();
		long get_fire_life();
		int get_bomb_power(){return m_bomb_power;};
		void ui_update();
	};
private:
	bool resize(int w, int h);

public:
	Tiled** m_tiled;
	Tiled* get_tiled(const Position & p){ return &m_tiled[p.get_x()][p.get_y()];};
	Tiled* get_tiled(int x, int y){ return &m_tiled[x][y];};
	int m_w,m_h;

	std::vector<Position> m_born_position;
public:
	Map();
	~Map();
	void print()
	{
#if 0
		system("cls");
		for(int w=0;w<m_w;w++)
		{
			for(int h=0;h<m_h;h++)
			{
				if(m_tiled[w][h].is_put_bomb())
					printf("%s","O");
				else if(m_tiled[w][h].m_fire)
					printf("%s","+");
				else
				{
					switch(m_tiled[w][h].m_p)
					{
					case 0://null
						printf("%s"," ");
						break;
					case 1://block
						printf("%s","=");
						break;
					case 2://wall
						printf("%s","#");
						break;
					}
				}
			}
			printf("\n");
		}
#endif
	}
	void ui_update();

	void clear();

	void load();

	int get_width(){return m_w;};
	int get_height(){return m_h;};
	/*
	* set bomb only set a sprite to show Animate
	*/
	void Explode(int x, int y);
	void set_bomb(int x,int y,int _man_index,long _bomb_power);

	int get_plays_count();
	Position get_play_born_position(int _index);

public:
	std::vector<Creature*> m_creatrues;
	Creature * get_creature(int _index);
public:
	void on_die(int _index);

};


class BombManAI
{
public:
	Creature * man;
	BombManAI(int _map_width,int _map_height,Creature * _c)
	{
		man = _c;
	}
	~BombManAI()
	{
		man = NULL;
	}
	virtual void next_step() = 0;
};


typedef BombManAI * (*CreateBombManAIProc)(int _map_width,int _map_height,Creature * _c);
class AIModule
{
	HINSTANCE  _m_ai_1;
public:
	AIModule::AIModule()
	{
		_m_ai_1 = NULL;
	}
	AIModule::~AIModule()
	{
		if(_m_ai_1)
		{
			FreeLibrary(_m_ai_1);
			_m_ai_1 = NULL;
		}
	}
	BombManAI * Load(LPCTSTR _path,int _map_width,int _map_height,Creature * _c)
	{
		if(_m_ai_1)
		{
			FreeLibrary(_m_ai_1);
			_m_ai_1 = NULL;

		}
		_m_ai_1 = LoadLibrary(_path);
		if(_m_ai_1 == NULL)
		{
			return NULL;
		}
		CreateBombManAIProc _create_ai = (CreateBombManAIProc)GetProcAddress(_m_ai_1, (LPCSTR)"CreateBombManAI");
		if(_create_ai == NULL)
		{
			return NULL;
		}

		return _create_ai(_map_width, _map_height,_c);
	}
};


